﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Rappelz.GameServer.Network;
using Rappelz.GameServer.Scripting;

namespace Rappelz.GameServer
{
    public class FieldProp : GameObject
    {
        public interface IFieldPropDeleteHandler
        {
            void onFieldPropDelete(FieldProp prop);
        }

        public override bool IsFieldProp()
        {
            return true;
        }

// Function       :     protected bool GameObject::IsDeleteable()
// Function       :   public static struct StructFieldProp * StructFieldProp::Create(struct StructFieldProp::FieldPropDeleteHandler *, const struct GameContent::FIELD_PROP_RESPAWN_INFO *, const float &, const float &, const unsigned char)

        public static FieldProp Create(FieldProp.IFieldPropDeleteHandler pDeleteHandler, GameContent.FieldPropRespawnInfo pPropInfo, uint lifeTime)
        {
            FieldProp fp = new FieldProp(pDeleteHandler,pPropInfo);
            fp.nLifeTime = lifeTime;
            fp.SetCurrentXY(pPropInfo.x, pPropInfo.y);
            fp.m_PropInfo.layer = pPropInfo.layer;
            fp.m_layer = fp.m_PropInfo.layer;
            RappelzServer.Instance.AddObject(fp);
            Globals.Log.Debug("Adding FieldProp Layer {0} x: {1} y: {2}: {3}", fp.m_layer, fp.region_x, fp.region_y, GameContent.GetString(fp.m_pFieldPropBase.nPropTextId));
            return fp;
        }

        public override bool ProcDelete()
        {
            if (this.m_pDeleteHandler != null)
                this.m_pDeleteHandler.onFieldPropDelete(this);
//            (v1->baseclass_0.baseclass_0.baseclass_0.vfptr->__vecDelDtor)(v1, 1);
            return true;
        }
// Function       :   public void SetDeleteHandler(struct StructFieldProp::FieldPropDeleteHandler *)
// Function       :   public bool StructFieldProp::IsFieldProp()
// Function       :   public int GetPropId()
// Function       :   public float GetZOffset()
// Function       :   public float GetRotateX()
// Function       :   public float GetRotateY()
// Function       :   public float GetRotateZ()
// Function       :   public float GetScaleX()
// Function       :   public float GetScaleY()
// Function       :   public float GetScaleZ()
// Function       :   public bool IsHeightLocked()
// Function       :   public float GetLockHeight()
// Function       :   public bool IsExpireObject()
// Function       :   public unsigned long GetRegenTime()
// Function       :   public const struct FieldPropBase * GetFieldPropBase()
// Function       :   public const struct GameContent::FIELD_PROP_RESPAWN_INFO * GetRespawnInfo()
// Function       :   public int GetRemainCount()

        public bool IsUsable(Player pPlayer)
        {
            ArPosition pos;              //             = ArPosition ptr -60h
            List<uint> vList = new List<uint>();
// .text:0044020C vList           = std.vector<unsigned int,std.allocator<unsigned int> > ptr -50h
// .text:0044020C it              = std._Vector_iterator<unsigned int,std.allocator<unsigned int> > ptr -30h
// .text:0044020C itMonster       = StructCreature.iterator ptr -28h
// .text:0044020C guild_id        = dword ptr -1Ch
// .text:0044020C var_18          = dword ptr -18h
            byte layer;//           = byte ptr -0Dh
// .text:0044020C pPlayer         = dword ptr  8
            bool bUsable;
            bool bMonsterFinding;
// 
// Data           :   ebp Relative, [00000008], Param, Type: struct StructPlayer *, pPlayer
// Data           :   ebp Relative, [FFFFFFF3], Local, Type: bool, bUsable
// Data           :   ebp Relative, [FFFFFFF3], Local, Type: bool, bMonsterFinding
// Data           :   ebp Relative, [FFFFFFB0], Local, Type: class std.vector<unsigned int,std.allocator<unsigned int> >, vList
// Data           :   ebp Relative, [FFFFFFD0], Local, Type: class std._Vector_iterator<unsigned int,std.allocator<unsigned int> >, it
// Data           :   ebp Relative, [FFFFFFD8], Local, Type: struct StructCreature.iterator, itMonster
// Data           :   ebp Relative, [FFFFFFA0], Local, Type: struct ArPosition, pos
// Data           :   ebp Relative, [FFFFFFF3], Local, Type: unsigned char, layer
// Data           :   ebp Relative, [FFFFFFE4], Local, Type: int, guild_id


            if (!this.m_bIsCasting )
            {
                if (pPlayer.GetLevel() >= this.m_pFieldPropBase.nMinLevel)
                {
                    if (pPlayer.GetLevel() <= this.m_pFieldPropBase.nMaxLevel)
                    {
//                     if (limit_asura != 0)
//                         fpb.nLimit |= 8;
//                     if (limit_gaia != 0)
//                         fpb.nLimit |= 0x10;
//                     if (limit_deva != 0)
//                         fpb.nLimit |= 4;

                        bUsable = false;
                        if ((this.m_pFieldPropBase.nLimit & 0x800) != 0 && pPlayer.IsHunter())
                            bUsable = true;
                        if ((this.m_pFieldPropBase.nLimit & 0x400) != 0 && pPlayer.IsFighter())
                            bUsable = true;
                        if ((this.m_pFieldPropBase.nLimit & 0x1000) != 0 && pPlayer.IsMagician())
                            bUsable = true;
                        if ((this.m_pFieldPropBase.nLimit & 0x2000) != 0 && pPlayer.IsSummoner())
                            bUsable = true;

                        if (bUsable)
                        {
                            if (pPlayer.GetRace() != 3 || (this.m_pFieldPropBase.nLimit & 0x10) != 0)
                            {
                                if (pPlayer.GetRace() != 4 || (this.m_pFieldPropBase.nLimit & 4) != 0)
                                {
                                    if (pPlayer.GetRace() != 5 || (this.m_pFieldPropBase.nLimit & 8) != 0)
                                    {
                                        if (this.m_pFieldPropBase.nLimitJobId == 0 || this.m_pFieldPropBase.nLimitJobId == pPlayer.GetJobId())
                                        {
//                                             v8 = 56;
//                                             *(v2 - 24) = 56; this.m_pFieldPropBase.nActivateValue
//                                             *(v2 - 20) = 48; this.m_pFieldPropBase.nActivateId
                                            for(int x = 0; x < 2; ++x)
                                            {
                                                switch(this.m_pFieldPropBase.nActivateId[x])
                                                {
                                                    case 1:
                                                        Item item = pPlayer.FindItemByCode(this.m_pFieldPropBase.nActivateValue[x,0]);
                                                        if (item == null
                                                          || item.m_Instance.nCount < this.m_pFieldPropBase.nActivateValue[x,1])
                                                            return false;
                                                        break;
                                                    case 2:
                                                        if (pPlayer.GetQuestProgress(this.m_pFieldPropBase.nActivateValue[x,0]) != this.m_pFieldPropBase.nActivateValue[x,1])
                                                            return false;
                                                        break;

                                                    case 3:
                                                        if (pPlayer.GetCurrentSkillLevel(this.m_pFieldPropBase.nActivateValue[x,0]) < this.m_pFieldPropBase.nActivateValue[x,1])
                                                            return false;
                                                        break;

                                                    case 4:
                                                        if (this.m_pFieldPropBase.nActivateValue[x,0] != 0
                                                          && !pPlayer.IsWornByCode(this.m_pFieldPropBase.nActivateValue[x,0])
                                                          || this.m_pFieldPropBase.nActivateValue[x,1] == 0
                                                          && pPlayer.IsWornByCode(this.m_pFieldPropBase.nActivateValue[x,0]))
                                                            return false;
                                                        break;

                                                    case 11:
                                                    case 12:
                                                        pos = pPlayer.GetCurrentPosition(Globals.GetArTime());
                                                        RappelzServer.Instance.EnumMovableObject(pos, pPlayer.m_layer,12 * this.m_pFieldPropBase.nActivateValue[x,0], vList, false, true);
                                                        bMonsterFinding = false;
                                                        foreach (uint handle in vList)
                                                        {
                                                            Monster mob = Creature.get(handle) as Monster;
                                                            if (mob != null)
                                                            {
                                                                if (this.m_pFieldPropBase.nActivateValue[x,0] == 0)
                                                                {
                                                                    if (this.m_pFieldPropBase.nActivateId[x] != 11)
                                                                    {
                                                                        return false;
                                                                    }
                                                                    bMonsterFinding = true;
                                                                    break;
                                                                }
                                                                if (mob.GetMonsterId() == this.m_pFieldPropBase.nActivateValue[x,0])
                                                                {
                                                                    if (this.m_pFieldPropBase.nActivateId[x] != 11)
                                                                    {
                                                                        return false;
                                                                    }
                                                                    bMonsterFinding = true;
                                                                    break;
                                                                }
                                                            }
                                                        }
                                                        if (this.m_pFieldPropBase.nActivateId[x] == 11 && !bMonsterFinding)
                                                            return false;
                                                        break;

                                                    case 13:
                                                        layer = pPlayer.m_layer;

                                                        int nDungeonId = DungeonManager.Instance.GetDungeonID(pPlayer.mv.x, pPlayer.mv.y);
                                                        if (nDungeonId != this.m_pFieldPropBase.nActivateValue[x, 1]
                                                          || layer != 1
                                                          || pPlayer.m_nPartyId == 0
                                                          || !PartyManager.Instance.IsAttackTeamParty(pPlayer.m_nPartyId)
                                                          || GuildManager.Instance.GetRaidDungeonID(PartyManager.Instance.GetAttackTeamGuildID(pPlayer.m_nPartyId)) != nDungeonId
                                                          || !DungeonManager.Instance.IsSiegeBegin(nDungeonId)
                                                          || PartyManager.Instance.GetPartyType(pPlayer.m_nPartyId) != PartyManager.PartyType.SeigeAttackTeam
                                                          || DungeonManager.Instance.IsOwner(nDungeonId, this.m_pFieldPropBase.nActivateValue[x, 0], PartyManager.Instance.GetAttackTeamGuildID(pPlayer.m_nPartyId)))
                                                            return false;
                                                        break;


                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return true;
        }

        public bool Cast()
        {
            this.m_bIsCasting = true;
            return true;
        }
// Function       :   public bool StructFieldProp::CancelCast()

        public bool UseProp(Player pPlayer)
        {
            long cnt;
            long nItemCount;
            Item pNewItem = null;
            int i;
            bool result;

            this.m_bIsCasting = false;

            int oldUseCount = this.m_nUseCount;
            if (this.m_pFieldPropBase.nUseCount == 0 || Interlocked.Decrement(ref this.m_nUseCount) >= 0)
            {
                for(i = 0; i < 2; ++i)
                {
                    if ( this.m_pFieldPropBase.drop_info[i].code != 0)
                    {
                        if (Globals.GetRandomInt32(1, 100000000) <= this.m_pFieldPropBase.drop_info[i].ratio )
                        {
                            nItemCount = Globals.GetRandomInt32(this.m_pFieldPropBase.drop_info[i].min_count, this.m_pFieldPropBase.drop_info[i].max_count + 1);

                            Item ti = Item.AllocItem(0,this.m_pFieldPropBase.drop_info[i].code, nItemCount,ItemInstance.GenerateCode.ByFieldProp,
                                Globals.GetRandomInt32(this.m_pFieldPropBase.drop_info[i].min_level, this.m_pFieldPropBase.drop_info[i].max_level + 1),
                                -1,-1,-1,0,0,0,0,-1, (Elemental.Type)0, 0,0,0);

                            cnt = ti.m_Instance.nCount;
                            pNewItem = pPlayer.PushItem(ti, cnt, false);

                            if (pNewItem != null)
                            {
                                Messages.SendResult(pPlayer, 0xCC, 0, pNewItem.m_hHandle);
                            }
                            ServerLog.Log((ushort)0x961,pPlayer.GetAccountID(),pPlayer.GetSID(),ti.m_Instance.nLevel + 100 * ti.m_Instance.nEnhance,
                                ti.m_Instance.Code,ti.m_Instance.nCount,pNewItem.m_Instance.nCount,pPlayer.m_nGold,pPlayer.m_nGold,(long)pPlayer.mv.x,
                                (long)pPlayer.mv.y,0,pPlayer.GetAccountName(),pPlayer. GetName(),"","PICK");
                            if (pNewItem.m_hHandle != ti.m_hHandle)
                                Item.PendFreeItem(ti);
                        }
                    }
                }

                if (!String.IsNullOrEmpty(this.m_pFieldPropBase.strScript) && this.m_pFieldPropBase.strScript.Length > 2)
                {
                    LuaVM.Instance.RunString(pPlayer, this.m_pFieldPropBase.strScript);
                }
                if (this.m_nUseCount == 0)
                {
                    RappelzServer.Instance.RemoveObject(this);
                    RappelzServer.Instance.DeleteObject(this);
                }
                result = true;
            }
            else
            {
                Interlocked.Increment(ref this.m_nUseCount);
                result = false;
            }
            return result;
        }

        
        public uint GetCastingDelay()
        {
            return this.m_pFieldPropBase.nCastingTime;
        }
// Function       :   public void StructFieldProp(const struct StructFieldProp &)
// Function       :   private void StructFieldProp::StructFieldProp(struct StructFieldProp::FieldPropDeleteHandler *, const struct GameContent::FIELD_PROP_RESPAWN_INFO *)
        private FieldProp(FieldProp.IFieldPropDeleteHandler pDeleteHandler, GameContent.FieldPropRespawnInfo pPropInfo)
        {
            this.m_bIsCasting = false;
            MemoryPool.AllocMiscHandle(this);
            this.m_nArObjectType = 0;
            this.m_pFieldPropBase = FieldPropManager.Instance.GetFieldPropBase(pPropInfo.nPropId);
            this.m_pDeleteHandler = pDeleteHandler;
            this.m_PropInfo = pPropInfo;
            this.nLifeTime = this.m_pFieldPropBase.nLifeTime;
            this.m_nRegenTime = Globals.GetArTime();
            this.m_nUseCount = this.m_pFieldPropBase.nUseCount;
            if (this.m_pFieldPropBase.nUseCount == 0)
                this.m_nUseCount = 1;
        }

        public uint m_nRegenTime;                                           // 0xBC
        public IFieldPropDeleteHandler m_pDeleteHandler;                    // 0xC0
        public FieldPropBase m_pFieldPropBase = new FieldPropBase();        // 0xC4
        public GameContent.FieldPropRespawnInfo m_PropInfo;                 // 0xC8
        public int m_nUseCount;                                             // 0xCC
        public bool m_bIsCasting;                                           // 0xD0
        public uint nLifeTime;

    }
}
